/*
 * Copyright 2002-2007 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package jacky.lanlan.song.concurrent;

import jacky.lanlan.song.reflection.ClassUtils;

/**
 * Simple customizable helper class for creating threads. Provides various bean properties, such as
 * thread name prefix, thread priority, etc.
 * 
 * <p>
 * Serves as base class for thread factories such as
 * {@link org.springframework.scheduling.concurrent.CustomizableThreadFactory}.
 * 
 * @author Juergen Hoeller
 * @since 2.0.3
 * @see org.springframework.scheduling.concurrent.CustomizableThreadFactory
 */
public class CustomizableThreadCreator {
	
	private final Object monitor = new Object();
	
	private String threadNamePrefix;
	
	private int threadPriority = Thread.NORM_PRIORITY;
	
	private boolean daemon = false;
	
	private ThreadGroup threadGroup;
	
	private int threadCount = 0;
	
	/**
	 * Create a new CustomizableThreadCreator with default thread name prefix.
	 */
	public CustomizableThreadCreator() {
		this(null);
	}
	
	/**
	 * Create a new CustomizableThreadCreator with the given thread name prefix.
	 * 
	 * @param threadNamePrefix
	 *          the prefix to use for the names of newly created threads
	 */
	public CustomizableThreadCreator(String threadNamePrefix) {
		setThreadNamePrefix(threadNamePrefix);
	}
	
	/**
	 * Specify the prefix to use for the names of newly created threads. Default is
	 * "SimpleAsyncTaskExecutor-".
	 */
	public void setThreadNamePrefix(String threadNamePrefix) {
		this.threadNamePrefix = (threadNamePrefix != null ? threadNamePrefix : getDefaultThreadNamePrefix());
	}
	
	/**
	 * Return the thread name prefix to use for the names of newly created threads.
	 */
	public String getThreadNamePrefix() {
		return this.threadNamePrefix;
	}
	
	/**
	 * Set the priority of the threads that this factory creates. Default is 5.
	 * 
	 * @see java.lang.Thread#NORM_PRIORITY
	 */
	public void setThreadPriority(int threadPriority) {
		this.threadPriority = threadPriority;
	}
	
	/**
	 * Return the priority of the threads that this factory creates.
	 */
	public int getThreadPriority() {
		return this.threadPriority;
	}
	
	/**
	 * Set whether this factory is supposed to create daemon threads, just executing as long as the
	 * application itself is running.
	 * <p>
	 * Default is "false": Concrete factories usually support explicit cancelling. Hence, if the
	 * application shuts down, Runnables will by default finish their execution.
	 * <p>
	 * Specify "true" for eager shutdown of threads which still actively execute a Runnable.
	 * 
	 * @see java.lang.Thread#setDaemon
	 */
	public void setDaemon(boolean daemon) {
		this.daemon = daemon;
	}
	
	/**
	 * Return whether this factory should create daemon threads.
	 */
	public boolean isDaemon() {
		return this.daemon;
	}
	
	/**
	 * Specify the name of the thread group that threads should be created in.
	 * 
	 * @see #setThreadGroup
	 */
	public void setThreadGroupName(String name) {
		this.threadGroup = new ThreadGroup(name);
	}
	
	/**
	 * Specify the thread group that threads should be created in.
	 * 
	 * @see #setThreadGroupName
	 */
	public void setThreadGroup(ThreadGroup threadGroup) {
		this.threadGroup = threadGroup;
	}
	
	/**
	 * Return the thread group that threads should be created in (or <code>null</code>) for the
	 * default group.
	 */
	public ThreadGroup getThreadGroup() {
		return this.threadGroup;
	}
	
	/**
	 * Template method for the creation of a Thread.
	 * <p>
	 * Default implementation creates a new Thread for the given Runnable, applying an appropriate
	 * thread name.
	 * 
	 * @param runnable
	 *          the Runnable to execute
	 * @see #nextThreadName()
	 */
	public Thread createThread(Runnable runnable) {
		Thread thread = new Thread(getThreadGroup(), runnable, nextThreadName());
		thread.setPriority(getThreadPriority());
		thread.setDaemon(isDaemon());
		return thread;
	}
	
	/**
	 * Return the thread name to use for a newly created thread.
	 * <p>
	 * Default implementation returns the specified thread name prefix with an increasing thread count
	 * appended: for example, "SimpleAsyncTaskExecutor-0".
	 * 
	 * @see #getThreadNamePrefix()
	 */
	protected String nextThreadName() {
		int threadNumber = 0;
		synchronized (this.monitor) {
			this.threadCount++;
			threadNumber = this.threadCount;
		}
		return getThreadNamePrefix() + threadNumber;
	}
	
	/**
	 * Build the default thread name prefix for this factory.
	 * 
	 * @return the default thread name prefix (never <code>null</code>)
	 */
	protected String getDefaultThreadNamePrefix() {
		return ClassUtils.getShortName(getClass()) + "-";
	}
	
}
